import numpy as np
import cv2

# 获取单应行矩阵
def get_home(img1,img2):
    sift = cv2.SIFT_create()
    # 提取特征点
    kp1, des1 = sift.detectAndCompute(img1, None)
    kp2, des2 = sift.detectAndCompute(img2, None)
    # 创建匹配器
    bf = cv2.BFMatcher(cv2.NORM_L1)
    # 特征点
    match = bf.knnMatch(des1, des2, k=2)
    # 过滤特征点
    good = []
    for m1,m2 in match:
        if m1.distance < 0.8 * m2.distance:
            good.append(m1)
    # 设置最少特征点为8
    min_match = 8
    if len(good) > min_match:
        img1_pts = []
        img2_pts = []
        for m in good:
            img1_pts.append(kp1[m.queryIdx].pt)
            img2_pts.append(kp2[m.trainIdx].pt)
        img1_pts = np.float32(img1_pts).reshape(-1, 1, 2)
        img2_pts = np.float32(img2_pts).reshape(-1, 1, 2)
        # 得出单应行矩阵
        H, mask = cv2.findHomography(img1_pts, img2_pts, cv2.RANSAC, 5.0)
        return H
    else:
        print("No matches found")
        exit()


# 进行拼接
def get_serch(img1,img2,H):
    # 找出角点
    h1, w1 = img1.shape[:2]
    pst1 = np.float32([[0, 0], [0, h1], [w1, h1], [w1, 0]]).reshape(-1, 1, 2)
    h2, w2 = img2.shape[:2]
    pst2 = np.float32([[0, 0], [0, h2], [w2, h2], [w2, 0]]).reshape(-1, 1, 2)
    # 计算变换
    dst1 = cv2.perspectiveTransform(pst1, H)
    # 拼接
    dst = np.concatenate((dst1, pst2), axis=0)
    # 计算最小最大坐标
    [x_min,y_min] = np.int32(dst.min(axis=0).ravel()-0.5)
    [x_max, y_max] = np.int32(dst.max(axis=0).ravel() + 0.5)
    # 平移的距离
    transform_dst = [-x_min, -y_min]
    transform_array = np.array([[1,0,transform_dst[0]],
                                [0,1,transform_dst[1]],
                                [0,0,1]])
    # 平移
    result_img = cv2.warpPerspective(img1, transform_array.dot(H), (x_max - x_min, y_max - y_min))
    # 将img2粘贴到result_img
    result_img[transform_dst[1]:transform_dst[1]+h2, transform_dst[0]:transform_dst[0]+w2] = img2
    return result_img


img1 = cv2.imread("C:\\Users\\86191\\Pictures\\Saved Pictures\\Camera Roll\\f1.jpg")
img2 = cv2.imread("C:\\Users\\86191\\Pictures\\Saved Pictures\\Camera Roll\\f21.jpg")
# 设置大小
img1 = cv2.resize(img1,(680,480))
img2 = cv2.resize(img2,(680,480))
# 水平拼接
hs = np.hstack((img1,img2))
H = get_home(img1,img2)
result_img = get_serch(img1,img2,H)
cv2.imshow("result",result_img)
cv2.waitKey(0)
